<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Example: Creating a Slider from Existing Markup</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.4.0pr3/build/cssgrids/grids-min.css">
    <link rel="stylesheet" href="../assets/css/main.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <script src="../../build/yui/yui-min.js"></script>
</head>
<body>

<div id="doc">
    <h1>Example: Creating a Slider from Existing Markup</h1>

    

    <div class="yui3-g">
        <div id="main" class="yui3-u">
            <div class="content"><style scoped>
    #demo {
        background: #fff;
        border: 1px solid #999;
        color: #000;
    }

    #demo .demo-content {
        padding: 1ex 1em;
    }

    #volume_control {
        height: 25px;
        line-height: 25px;
        background: url(../assets/slider/images/sprite.png) repeat-x 0 0;
        position: relative;
    }

    #volume_control label {
        font-weight: bold;
        margin: 0 1ex 0 1em;
        zoom: 1;
    }

    #volume {
        border: 1px inset #999;
        height: 16px;
        margin-top: 3px;
        padding: 0 3px;
        text-align: right;
        width: 2em;
    }

    /* Support open/close action for the slider */
    #demo .volume-hide #volume_slider {
        display: none;
    }

    #volume_icon {
        background: url(../assets/slider/images/sprite.png) no-repeat 0 -25px;
        border: 0 none;
        height: 25px;
        vertical-align: top;
        width: 31px;
    }

    /* move the button text offscreen left */
    #volume_icon p {
        text-indent: -9999px;
    }

    /*
     * adjust the speaker icon sprite in accordance with volume level and
     * active state
    */
    #demo .volume-hide .level_0 { background-position: 0 -25px; }
    #demo .volume-hide .level_1 { background-position: 0 -50px; }
    #demo .volume-hide .level_2 { background-position: 0 -75px; }
    #demo .volume-hide .level_3 { background-position: 0 -100px; }

    #demo .level_0,
    #demo .level_0:hover {
        background-position: 0 -125px;
    }
    #demo .level_1,
    #demo .level_1:hover {
        background-position: 0 -150px;
    }
    #demo .level_2,
    #demo .level_2:hover {
        background-position: 0 -175px;
    }
    #demo .level_3,
    #demo .level_3:hover {
        background-position: 0 -200px;
    }

    #volume_slider {
        position: absolute;
        top: 25px;
    }

    /* rail image on the containing box rather than the rail element */
    #volume_slider {
        background: url(../assets/slider/images/sprite.png) no-repeat 0 -259px;
        height: 116px;
        width: 31px;
        padding-top: 9px;
        cursor: arrow;
    }

    #volume_slider .yui3-slider-rail {
        background-image: none;
        width: 31px;
    }

    #volume_slider .yui3-slider-thumb {
        height: 17px;
        width: 31px;
        overflow: hidden;
    }

    #volume_slider .yui3-slider-thumb img {
        position: absolute;
        top: -225px;
    }

    #volume_slider .yui3-slider-disabled .yui3-slider-thumb img {
        top: -242px;
    }

    #demo_sprite {
        display: inline;
        float: left;
        margin-right: 1em;
    }
</style>

<div class="intro">
    <p>This example illustrates a few points:</p>
    <ol>
        <li>How to create a Slider using existing markup</li>
        <li>How to disable a Slider</li>
        <li>How to use an image sprite to create a custom Slider skin</li>
    </ol>

    <p>The visualization of the Slider is based on the volume control in Mac OS X 10.5, with additional controls included for illustration.  <strong>Click on the speaker icon to show the Slider</strong>.</p>
</div>

<div class="example">
    <div id="demo" class="yui3-skin-sam">

    <div id="volume_control" class="volume-hide">
        <label for="volume">volume</label><input type="text" size="3" maxlength="3" name="volume" id="volume" value="50">
        <button type="button" id="volume_icon" class="level_2" title="Open volume slider"><p>Open</p></button>
        <span id="volume_slider">
            <span class="yui3-slider-rail">
                <span class="yui3-slider-thumb"><img src="../assets/slider/images/sprite.png" height="384" width="31"></span>
            </span>
        </span>
        <label for="mute"><input type="checkbox" id="mute"> mute</label>
    </div>

    <div class="demo-content">
        <p>Nulla facilisi. In vel sem. Morbi id urna in diam dignissim feugiat. Proin molestie tortor eu velit. Aliquam erat volutpat. Nullam ultrices, diam tempus vulputate egestas, eros pede varius leo, sed imperdiet lectus est ornare odio.</p>
        <p>Phasellus wisi purus, interdum vitae, rutrum accumsan, viverra in, velit. Sed enim risus, congue non, tristique in, commodo eu, metus. Aenean tortor mi, imperdiet id, gravida eu, posuere eu, felis.</p>
    </div>
</div>
<script type="text/javascript">
YUI().use("slider", function (Y) {

var control    = Y.one('#volume_control'),
    volInput   = Y.one('#volume'),
    icon       = Y.one('#volume_icon'),
    mute       = Y.one('#mute'),
    open       = false,
    level      = 2,
    beforeMute = 0,
    wait,
    volume;

Y.one("#volume_slider").setStyle('left',icon.get('offsetLeft')+'px');

volume = new Y.Slider({
    axis  : 'y',
    min   : 100,
    max   : 0,
    value : 50,
    length: '105px'
});

volume.renderRail = function () {
    return Y.one( "#volume_slider span.yui3-slider-rail" );
};
volume.renderThumb = function () {
    return this.rail.one( "span.yui3-slider-thumb" );
};

volume.render( "#volume_slider" );

// Initialize event listeners
volume.after('valueChange', updateInput);
volume.after('valueChange', updateIcon);

mute.on('click', muteVolume);

volInput.on({
    keydown : handleInput,
    keyup   : updateVolume
});

icon.on('click', showHideSlider);

Y.one( 'doc' ).on('click', handleDocumentClick );

// Support functions
function updateInput(e) {
    if (e.src !== 'KEY') {
        volInput.set('value',e.newVal);
    }
}

function updateIcon(e) {
    var newLevel = e.newVal && Math.ceil(e.newVal / 34);

    if (level !== newLevel) {
        icon.replaceClass('level_'+level, 'level_'+newLevel);
        level = newLevel;
    }
}

function muteVolume(e) {
    var disabled = !volume.get('disabled');
    volume.set('disabled', disabled);

    if (disabled) {
        beforeMute = volume.getValue();
        volume.setValue(0);
        volInput.set('disabled','disabled');
    } else {
        volume.setValue(beforeMute);
        volInput.set('disabled','');
    }
}

function handleInput(e) {
    // Allow only numbers and various other control keys
    if (e.keyCode > 57) {
        e.halt();
    }
}

function updateVolume(e) {
    // delay input processing to give the user time to type
    if (wait) {
        wait.cancel();
    }

    wait = Y.later(400, null, function () {
        var value = parseInt(volInput.get('value'),10) || 0;

        if (value > 100) {
            volInput.set('value', 100);
            value = 100
        }

        volume.setValue( value );
    });
}

function showHideSlider(e) {
    control.toggleClass('volume-hide');
    open = !open;

    if (e) {
        e.preventDefault();
    }
}

function handleDocumentClick(e) {
    if (open && !icon.contains(e.target) &&
            !volume.get('boundingBox').contains(e.target)) {
        showHideSlider();
    }
}

});
</script>

</div>

<h3 id="prog_enh">Progressive Enhancement</h3>
<p>The <a href="http://en.wikipedia.org/wiki/Progressive_enhancement">Progressive Enhancement</a> strategy recommends that your page not contain markup that will only be useful in cases where JavaScript is available.  For this reason, Slider does not include an <code>HTML_PARSER</code> to reuse existing markup.  However, it is possible to override a couple methods to accomplish the task.</p>

<p>The starting markup for the volume control area is as follows:</p>

<pre class="code prettyprint">&lt;div id=&quot;volume_control&quot; class=&quot;volume-hide&quot;&gt;
    &lt;label for=&quot;volume&quot;&gt;volume&lt;&#x2F;label&gt;&lt;input type=&quot;text&quot; size=&quot;3&quot; maxlength=&quot;3&quot; name=&quot;volume&quot; id=&quot;volume&quot; value=&quot;50&quot;&gt;
    &lt;button type=&quot;button&quot; id=&quot;volume_icon&quot; class=&quot;level_2&quot; title=&quot;Open volume slider&quot;&gt;&lt;p&gt;Open&lt;&#x2F;p&gt;&lt;&#x2F;button&gt;

    &lt;span id=&quot;volume_slider&quot;&gt;
        &lt;span class=&quot;yui3-slider-rail&quot;&gt;
            &lt;span class=&quot;yui3-slider-thumb&quot;&gt;&lt;img src=&quot;..&#x2F;assets&#x2F;slider&#x2F;images&#x2F;sprite.png&quot; height=&quot;384&quot; width=&quot;31&quot;&gt;&lt;&#x2F;span&gt;
        &lt;&#x2F;span&gt;
    &lt;&#x2F;span&gt;

    &lt;label for=&quot;mute&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mute&quot;&gt; mute&lt;&#x2F;label&gt;
&lt;&#x2F;div&gt;</pre>


<p>To tell the Slider to use the existing rail and thumb elements, override the <code>renderRail</code> and <code>renderThumb</code> methods.</p>

<pre class="code prettyprint">var volume = new Y.Slider({
    axis  : &#x27;y&#x27;,
    min   : 100, &#x2F;&#x2F; reverse min and max to make the top
    max   : 0,   &#x2F;&#x2F; equal 100 and the bottom 0
    value : 50,
    length: &#x27;105px&#x27;
});

&#x2F;&#x2F; Override renderRail to just return the existing rail node
volume.renderRail = function () {
    return Y.one( &quot;#volume_slider span.yui3-slider-rail&quot; );
};
&#x2F;&#x2F; Override renderThumb to just return the existing thumb node
volume.renderThumb = function () {
    return this.rail.one( &quot;span.yui3-slider-thumb&quot; );
};

volume.render( &quot;#volume_slider&quot; );</pre>


<h3 id="syncui">Hide and show the Slider</h3>
<p>By default, we want the Slider to be hidden until the user clicks on the speaker icon.  However, we want to support muting or changing the value of the Slider while it is hidden.</p>

<pre class="code prettyprint">var control = Y.one(&#x27;#volume_control&#x27;),
    icon    = Y.one(&#x27;#volume_icon&#x27;),
    open    = false;

function showHideSlider(e) {
    control.toggleClass(&#x27;volume-hide&#x27;);
    open = !open;

    if (e) {
        e.preventDefault();
    }
}

icon.on(&#x27;click&#x27;, showHideSlider);

&#x2F;&#x2F; Also support hiding the Slider when the user clicks outside the
&#x2F;&#x2F; Slider element.
function handleDocumentClick(e) {
    if (open &amp;&amp; !icon.contains(e.target) &amp;&amp;
            !volume.get(&#x27;boundingBox&#x27;).contains(e.target)) {
        showHideSlider();
    }
}

Y.one( &#x27;doc&#x27; ).on(&#x27;click&#x27;, handleDocumentClick );</pre>


<h3 id="demo_mute">Mute and unmute</h3>
<p>We want to disable the Slider and input and set the value to 0 if a user checks the mute checkbox.  The value should be returned to the last assigned value when unmuted.  To disable the Slider, set its <code>disabled</code> attribute to <code>true</code>.</p>

<pre class="code prettyprint">var volInput   = Y.one(&#x27;#volume&#x27;),
    mute       = Y.one(&#x27;#mute&#x27;),
    beforeMute = 0;

function muteVolume(e) {
    &#x2F;&#x2F; Set disabled to false if currently true; true if currently false
    var disabled = !volume.get(&#x27;disabled&#x27;);
    volume.set(&#x27;disabled&#x27;, disabled);

    if (disabled) {
        beforeMute = volume.getValue();
        volume.setValue(0);
        volInput.set(&#x27;disabled&#x27;,&#x27;disabled&#x27;);
    } else {
        volume.setValue(beforeMute);
        volInput.set(&#x27;disabled&#x27;,&#x27;&#x27;);
    }
}

mute.on(&#x27;click&#x27;, muteVolume);</pre>


<h3>Skinning and CSS</h3>
<img id="demo_sprite" src="../assets/slider/images/sprite.png" height="384" width="31" alt="Sprite of all custom image resources for this example">
<p>We'll be using the image sprite to the left to create a custom skin.  In this design, to keep things simple, the Slider's container and end caps are all rendered together at the bottom of the sprite.</p>

<p>Slider's thumb range is constrained by the rail element, so it wouldn't be appropriate to use this image as the rail's background&#8212;the thumb would slide off the ends.  Instead, the rail image is assigned as the background to the Slider's containing element <code>#volume_slider</code>.  Then the default skin background image is removed on the rail.</p>

<pre class="code prettyprint">&#x2F;* rail image on the containing box rather than the rail element *&#x2F;
#volume_slider {
    background: url(&quot;assets&#x2F;images&#x2F;sprite.png&quot;) no-repeat 0 -259px;
    height: 116px;
    width: 31px;
    padding-top: 9px;
}

#volume_slider .yui3-slider-rail {
    background-image: none;
    width: 31px;
}

#volume_slider .yui3-slider-thumb {
    height: 17px;
    width: 31px;
    overflow: hidden;
}

#volume_slider .yui3-slider-thumb img {
    position: absolute;
    top: -225px;
}

#volume_slider .yui3-slider-disabled .yui3-slider-thumb img {
    top: -242px;
}</pre>


<p>You can see the full CSS and JavaScript for the other controls in the <a href="#full_code_listing">Full Code Listing</a> below.</p>


<h3 id="full_code_listing">Full Code Listing</h3>
<p>Here is the full markup, CSS, and JavaScript for the entire example, including the volume input and mute controls, and CSS for placing the Slider and setting up the volume icon sprite positioning.</p>

<h4>Markup</h4>
<pre class="code prettyprint">&lt;div id=&quot;demo&quot;&gt;

    &lt;div id=&quot;volume_control&quot; class=&quot;volume-hide&quot;&gt;
        &lt;label for=&quot;volume&quot;&gt;volume&lt;&#x2F;label&gt;&lt;input type=&quot;text&quot; size=&quot;3&quot; maxlength=&quot;3&quot; name=&quot;volume&quot; id=&quot;volume&quot; value=&quot;50&quot;&gt;
        &lt;button type=&quot;button&quot; id=&quot;volume_icon&quot; class=&quot;level_2&quot; title=&quot;Open volume slider&quot;&gt;&lt;p&gt;Open&lt;&#x2F;p&gt;&lt;&#x2F;button&gt;
        &lt;span id=&quot;volume_slider&quot;&gt;
            &lt;span class=&quot;yui3-slider-rail&quot;&gt;
                &lt;span class=&quot;yui3-slider-thumb&quot;&gt;&lt;img src=&quot;..&#x2F;assets&#x2F;slider&#x2F;images&#x2F;sprite.png&quot; height=&quot;384&quot; width=&quot;31&quot;&gt;&lt;&#x2F;span&gt;
            &lt;&#x2F;span&gt;
        &lt;&#x2F;span&gt;
        &lt;label for=&quot;mute&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mute&quot;&gt; mute&lt;&#x2F;label&gt;
    &lt;&#x2F;div&gt;

    &lt;div class=&quot;demo-content&quot;&gt;
        &lt;p&gt;Nulla facilisi. In vel sem. Morbi id urna in diam dignissim feugiat. Proin molestie tortor eu velit. Aliquam erat volutpat. Nullam ultrices, diam tempus vulputate egestas, eros pede varius leo, sed imperdiet lectus est ornare odio.&lt;&#x2F;p&gt;
        &lt;p&gt;Phasellus wisi purus, interdum vitae, rutrum accumsan, viverra in, velit. Sed enim risus, congue non, tristique in, commodo eu, metus. Aenean tortor mi, imperdiet id, gravida eu, posuere eu, felis.&lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;</pre>


<h4 id="full_js">JavaScript</h4>
<pre class="code prettyprint">YUI().use(&quot;slider&quot;, function (Y) {

var control    = Y.one(&#x27;#volume_control&#x27;),
    volInput   = Y.one(&#x27;#volume&#x27;),
    icon       = Y.one(&#x27;#volume_icon&#x27;),
    mute       = Y.one(&#x27;#mute&#x27;),
    open       = false,
    level      = 2,
    beforeMute = 0,
    wait,
    volume;

&#x2F;&#x2F; The style.top is known because of a fixed height control bar, but the
&#x2F;&#x2F; style.left remains unknown until run time.
Y.one(&quot;#volume_slider&quot;).setStyle(&#x27;left&#x27;,icon.get(&#x27;offsetLeft&#x27;)+&#x27;px&#x27;);

volume = new Y.Slider({
    axis  : &#x27;y&#x27;,
    min   : 100,
    max   : 0,
    value : 50,
    length: &#x27;105px&#x27;
});

volume.renderRail = function () {
    return Y.one( &quot;#volume_slider span.yui3-slider-rail&quot; );
};
volume.renderThumb = function () {
    return this.rail.one( &quot;span.yui3-slider-thumb&quot; );
};

volume.render( &quot;#volume_slider&quot; );

&#x2F;&#x2F; Initialize event listeners
volume.after(&#x27;valueChange&#x27;, updateInput);
volume.after(&#x27;valueChange&#x27;, updateIcon);

mute.on(&#x27;click&#x27;, muteVolume);

volInput.on({
    keydown : handleInput,
    keyup   : updateVolume
});

icon.on(&#x27;click&#x27;, showHideSlider);

Y.one( &#x27;doc&#x27; ).on(&#x27;click&#x27;, handleDocumentClick );

&#x2F;&#x2F; Support functions
function updateInput(e) {
    if (e.src !== &#x27;KEY&#x27;) {
        volInput.set(&#x27;value&#x27;,e.newVal);
    }
}

function updateIcon(e) {
    var newLevel = e.newVal &amp;&amp; Math.ceil(e.newVal &#x2F; 34);

    if (level !== newLevel) {
        icon.replaceClass(&#x27;level_&#x27;+level, &#x27;level_&#x27;+newLevel);
        level = newLevel;
    }
}

function muteVolume(e) {
    var disabled = !volume.get(&#x27;disabled&#x27;);
    volume.set(&#x27;disabled&#x27;, disabled);

    if (disabled) {
        beforeMute = volume.getValue();
        volume.setValue(0);
        volInput.set(&#x27;disabled&#x27;,&#x27;disabled&#x27;);
    } else {
        volume.setValue(beforeMute);
        volInput.set(&#x27;disabled&#x27;,&#x27;&#x27;);
    }
}

function handleInput(e) {
    &#x2F;&#x2F; Allow only numbers and various other control keys
    if (e.keyCode &gt; 57) {
        e.halt();
    }
}

function updateVolume(e) {
    &#x2F;&#x2F; delay input processing to give the user time to type
    if (wait) {
        wait.cancel();
    }

    wait = Y.later(400, null, function () {
        var value = parseInt(volInput.get(&#x27;value&#x27;),10) || 0;

        if (value &gt; 100) {
            volInput.set(&#x27;value&#x27;, 100);
            value = 100
        }

        volume.setValue( value );
    });
}

function showHideSlider(e) {
    control.toggleClass(&#x27;volume-hide&#x27;);
    open = !open;

    if (e) {
        e.preventDefault();
    }
}

function handleDocumentClick(e) {
    if (open &amp;&amp; !icon.contains(e.target) &amp;&amp;
            !volume.get(&#x27;boundingBox&#x27;).contains(e.target)) {
        showHideSlider();
    }
}

});</pre>


<h4 id="full_css">CSS</h4>
<pre class="code prettyprint">#demo {
    background: #fff;
    border: 1px solid #999;
    color: #000;
}

#demo .demo-content {
    padding: 1ex 1em;
}

#volume_control {
    height: 25px;
    line-height: 25px;
    background: url(&quot;assets&#x2F;images&#x2F;sprite.png&quot;) repeat-x 0 0;
    position: relative;
}

#volume_control label {
    font-weight: bold;
    margin: 0 1ex 0 1em;
    zoom: 1;
}

#volume {
    border: 1px inset #999;
    height: 16px;
    margin-top: 3px;
    padding: 0 3px;
    text-align: right;
    width: 2em;
}

&#x2F;* Support open&#x2F;close action for the slider *&#x2F;
#demo .volume-hide #volume_slider {
    display: none;
}

#volume_icon {
    background: url(&quot;assets&#x2F;images&#x2F;sprite.png&quot;) no-repeat 0 -25px;
    border: 0 none;
    height: 25px;
    vertical-align: top;
    width: 31px;
}

&#x2F;* move the button text offscreen left *&#x2F;
#volume_icon p {
    text-indent: -9999px;
}

&#x2F;*
 * adjust the speaker icon sprite in accordance with volume level and
 * active state
*&#x2F;
#demo .volume-hide .level_0 { background-position: 0 -25px; }
#demo .volume-hide .level_1 { background-position: 0 -50px; }
#demo .volume-hide .level_2 { background-position: 0 -75px; }
#demo .volume-hide .level_3 { background-position: 0 -100px; }

#demo .level_0,
#demo .level_0:hover {
    background-position: 0 -125px;
}
#demo .level_1,
#demo .level_1:hover {
    background-position: 0 -150px;
}
#demo .level_2,
#demo .level_2:hover {
    background-position: 0 -175px;
}
#demo .level_3,
#demo .level_3:hover {
    background-position: 0 -200px;
}

#volume_slider {
    position: absolute;
    top: 25px;
}

&#x2F;* rail image on the containing box rather than the rail element *&#x2F;
#volume_slider {
    background: url(&quot;assets&#x2F;images&#x2F;sprite.png&quot;) no-repeat 0 -259px;
    height: 116px;
    width: 31px;
    padding-top: 9px;
    cursor: arrow;
}

#volume_slider .yui3-slider-rail {
    background-image: none;
    width: 31px;
}

#volume_slider .yui3-slider-thumb {
    height: 17px;
    width: 31px;
    overflow: hidden;
}

#volume_slider .yui3-slider-thumb img {
    position: absolute;
    top: -225px;
}

#volume_slider .yui3-slider-disabled .yui3-slider-thumb img {
    top: -242px;
}

#demo_sprite {
    display: inline;
    float: left;
    margin-right: 1em;
}</pre>


</div>
        </div>

        <div id="sidebar" class="yui3-u">
            

            
                <div class="sidebox">
                    <div class="hd">
                        <h2 class="no-toc">Examples</h2>
                    </div>

                    <div class="bd">
                        <ul class="examples">
                            
                                
                                    <li data-description="The basics of setting up a horizontal and vertical Slider">
                                        <a href="slider-basic.html">Basic Sliders</a>
                                    </li>
                                
                            
                                
                                    <li data-description="Creating a vertical Slider from existing markup">
                                        <a href="slider-from-markup.html">Creating a Slider from Existing Markup</a>
                                    </li>
                                
                            
                                
                                    <li data-description="Specifying an alternate skin for a Slider instance">
                                        <a href="slider-skin.html">Alternate Skins</a>
                                    </li>
                                
                            
                                
                            
                                
                            
                                
                            
                        </ul>
                    </div>
                </div>
            

            
                <div class="sidebox">
                    <div class="hd">
                        <h2 class="no-toc">Examples That Use This Component</h2>
                    </div>

                    <div class="bd">
                        <ul class="examples">
                            
                                
                            
                                
                            
                                
                            
                                
                                    <li data-description="Shows how to use Overlay&#x27;s constrainment support, to limit the XY value which can be set for an Overlay.">
                                        <a href="../overlay/overlay-constrain.html">Constrain Support</a>
                                    </li>
                                
                            
                                
                                    <li data-description="Use StyleSheet to adjust the CSS rules applying a page theme from user input">
                                        <a href="../stylesheet/stylesheet-theme.html">Adjusting a Page Theme on the Fly</a>
                                    </li>
                                
                            
                                
                                    <li data-description="Example Photo Browser application.">
                                        <a href="../dd/photo-browser.html">Photo Browser</a>
                                    </li>
                                
                            
                        </ul>
                    </div>
                </div>
            
        </div>
    </div>
</div>

<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>

</body>
</html>
